#_*_coding:gbk_*_

# Copyright (c) 2008 crunch <hymm91@gmail.com>
# All rights reserved

#$Id: daemon.py 44 2013-03-09 05:32:48Z hymm91@gmail.com $
__author__ = 'crunch <hymm91@gmail.com>'
__version__ = '$Revision: 44 $'

import os
import sys, signal
from wytool import logger

_daemon = 0
_sig_func = None

def _sig_term(sig_no, frame):
    global _sig_func
    if _sig_func:
        _sig_func()
    signal.signal(signal.SIGTERM, _sig_term)

def _sig_int(sig_no, frame):
    global _sig_func
    if _sig_func:
        _sig_func()
    signal.signal(signal.SIGINT, _sig_int)

def getpwnam(name, pwfile=None):
    """Return pasword database entry for the given user name.
    
    Example from the Python Library Reference.
    """
    
    if not pwfile:
        pwfile = '/etc/passwd'

    f = open(pwfile)
    while 1:
        line = f.readline()
        if not line:
            f.close()
            raise KeyError, name
        entry = tuple(line.strip().split(':', 6))
        if entry[0] == name:
            f.close()
            return entry

def daemon(nochdir, noclose):
    pid = os.fork()
    if pid == -1:
        return -1
    if pid != 0:
        sys.exit(0)

    os.setsid()

    pid = os.fork()
    if pid == -1:
        return -1
    if pid != 0:
        sys.exit(0)


    os.umask(022)

    if not nochdir:
        os.chdir("/")
    
    if (not noclose):
        daemon_fd_close()
    global _daemon
    _daemon = 1
    return 0

def daemon_fd_close():
    try:
        fd = open("/dev/null")
    except:
        pass
    else:
        os.dup2(fd.fileno(), sys.stdin.fileno())
        os.dup2(fd.fileno(), sys.stdout.fileno())
        os.dup2(fd.fileno(), sys.stderr.fileno())
        if fd.fileno() > sys.stderr.fileno():
            fd.close()
    
def isdaemon(self):
    global _daemon
    return _daemon

def remove_pidfile(pid_file):
    if not pid_file:
        return 0
    try:
        os.unlink(pid_file)
    except:
        sys.stderr.write("Colud not remove the pid file %s.\n" % pid_file)
        return -1
    return 0
    
def save_pid(pid, pid_file):
    try:
        fd = open(pid_file, "w")
    except IOError, e:
        sys.stderr.write("Could not open the pid file %s for writing\n" % pid_file)
        return (-1, e)
    else:
        fd.write("%ld\n" % pid)
        try:
            fd.close()
        except IOError, e:
            sys.stderr.write("Could not close the pid file %s.\n" % pid_file)
            return (-1, e)

    return (0, None)

def ident_user(username):
    pw = getpwnam(username)

    if not pw:
        sys.stderr.write("can't find the user %s to switch to\n" % username)
        return (-1, ["can't find the user %s to switch to\n" % username])
    try:
        os.setgid(int(pw[3])) 
        os.setuid(int(pw[2]))
    except OSError, e:
        sys.stderr.write("failed to assume identity of user %s\n" % username)
        return (-1, e)
    return (0, None)

def install_signal(sig_func=None):
    global _sig_func
    _sig_func = sig_func
    signal.signal(signal.SIGINT, _sig_int)
    signal.signal(signal.SIGTERM, _sig_term)

    if not sys.platform.startswith('win'):
        ingores = (signal.SIGTTOU, signal.SIGTTIN, signal.SIGTSTP, signal.SIGHUP, \
                signal.SIGPIPE, signal.SIGPROF, signal.SIGQUIT)
        for v in ingores:
            signal.signal(v, signal.SIG_IGN)


def run(app='', argv='', pidfile='', logfile='', user='', callback=None, \
        daemon_flag=1, scriber_ip='', scriber_port=0, app_ip='unknow', app_port=0, \
        category='fl_error'):
    if daemon_flag:
        daemon(nochdir = None, noclose = True)
    if user:
        res, desc = ident_user(user)
        if res != 0:
            sys.stderr.write('%s\n' % desc[-1])
            sys.exit(desc[0])

    if pidfile:
        try:
            tmp_file = file(pidfile)
        except:
            (res, desc) =  save_pid(os.getpid(), pidfile)
            if res != 0:
                sys.stderr.write('%s\n' % desc[-1])
                sys.exit(desc[0])
        else:
            val = tmp_file.read().strip()
            sys.stderr.write('another copy pid:%s is running.\n' % val)
            sys.exit(9)
    _logger = None
    if logfile:
        _logger = logger.logger()
        res, desc = _logger.log_open(logfile)
        if res != 0:
            sys.stderr.write("%s\n" % desc[-1])
            sys.exit(res)
      
    if daemon_flag:
        daemon_fd_close()
        
    if _logger:
        _logger.set_appinfo(app, app_ip, app_port)
        if scriber_ip:
            _logger.set_scriber(scriber_ip, scriber_port, category)
        _logger.debug_log('%s started: %s' % (app, argv))

        _logger.pulse(logger.START_MODE)

    res = callback(_logger)

    if pidfile:
        remove_pidfile(pidfile)

    if _logger:
        _logger.debug_log('%s quited.' % app)        
        _logger.pulse(logger.FINISH_MODE)

        _logger.log_close()

    return res


if __name__ == '__main__':
    #import pdb
    #pdb.set_trace()
    #(res, desc) = ident_user('root')
    #print res
    #print desc
    (res, desc) = ident_user('crawler')
    print res
    print desc
    sys.exit(0)
    daemon(nochdir = None, noclose = None)
    import time
    while (1):
        time.sleep(1)



    
